#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

#include "nstar_m26_api.h"
#include "syscfg.h"

#define NET_UP      0
#define NET_DOWN    1

#define FIILTER_DEPTH 3	//滤波级数，必须1-32
#define MASK (0xffffffff >> (32-FIILTER_DEPTH))


extern unsigned char M26_get_sta(void);

struct netsta {
    char ifname[12];
    unsigned char Sta;
    unsigned char oldsta;
    unsigned int reg;
};

static unsigned char _sys_ping_res(const char *ipaddr, const char *netif) {
    FILE *fp; 
    char arg[80];  
    char buf[128];
    unsigned char ret= 1;
    memset((unsigned char*)buf, 0, 64);
	memset(arg, 0, sizeof(arg));
    if(netif != NULL)
        snprintf(arg, 80, "ping %s -I %s -q -c 1", ipaddr, netif);
    else
        snprintf(arg, 80, "ping %s -q -c 1", ipaddr);
    if((fp=popen(arg, "r"))!=NULL)   
	{
		while(fgets(buf, sizeof(buf)-1, fp)!=NULL)   
		{   
           if (NULL != strstr(buf, " 0% packet loss") ) {
                ret = 0;
           }        
		}   
		pclose(fp);    
	} 
    //printf("%s, res %d %s\n", arg, ret, ret==1 ? "err": "ok");
    return ret;
}


static unsigned char __myfilter(unsigned int *reg, unsigned char sta) {
	*reg = ((*reg) << 1) | (sta&0x1);
	if(((*reg)&MASK) == MASK){
		return NET_DOWN;
	}
	else {
		return NET_UP;
	}
}

static void _net_err_check(struct netsta *n) {
#define TEST_DNS_ADDR "114.114.114.114"    
    char buf[32];
    unsigned char res = 0;
    unsigned int sip = cfgget_sip();
    sprintf(buf, "%d.%d.%d.%d", sip>>24, (sip>>16)&0xff, (sip>>8)&0xff, sip&0xff);
    if( 0 != _sys_ping_res(buf, n->ifname)) { 
        if( 0 != _sys_ping_res(TEST_DNS_ADDR, n->ifname)) { 
             res = 1;
        }
    }
    n->Sta = __myfilter(&n->reg, res);
}

static struct netsta n_4gsta={"usb0", NET_DOWN, NET_DOWN, 0xffffffff};
static struct netsta n_lansta={"eth0", NET_DOWN, NET_DOWN, 0xffffffff};


static void net4G_do_manage(void) {
    struct netsta *n = &n_4gsta;
    _net_err_check(n);
    if(n->Sta == NET_UP && n->oldsta != NET_UP){
        printf("4g net up\n");
    }else if(n->Sta == NET_DOWN && n->oldsta != NET_DOWN) {
        printf("4g net down\n");
        M26_do_reboot_module();
    }  
    n->oldsta = n->Sta;
}

static void _do_addremove_route(unsigned short metric) {
    FILE *fp;
    unsigned int gw = cfgget_gateway();
    char arg[80];  
    char buf[128];
    sprintf(arg, "route del default eth0");
    if((fp=popen(arg, "r"))!=NULL)   {
		while(fgets(buf, sizeof(buf)-1, fp)!=NULL)   
		{   
            //printf("%s\n", buf);  
		}   
		pclose(fp);    
	} 

    snprintf(arg, 80, "route add default gw %d.%d.%d.%d dev eth0 metric %d", \
            gw>>24, (gw>>16)&0xff, (gw>>8)&0xff, gw&0xff, metric);  
    if((fp=popen(arg, "r"))!=NULL)  {
		while(fgets(buf, sizeof(buf)-1, fp)!=NULL)   
		{   
            //printf("%s\n", buf);  
		}   
		pclose(fp);    
	} 
   
}

static void lan_do_manage(void) { 
    struct netsta *n = &n_lansta;
    _net_err_check(n);
    if(n->Sta == NET_UP && n->oldsta != NET_UP){
        printf("lan net up\n");
        _do_addremove_route(0);
    }else if(n->Sta == NET_DOWN && n->oldsta != NET_DOWN) {
        printf("lan net down\n");
        _do_addremove_route(100);
    }  
    n->oldsta = n->Sta;
}

#define dbg printf
void *net_manage(void *parm) {
    static unsigned char init=30;
    static volatile long tick = 0;
#define _TICK_SLEEP(n) app_sleep(&tick, n*1000)
#define _TICK_PEND()  app_pend_wake(tick)

    unsigned char t=3;
    while(1) {
    	if(_TICK_PEND()){
            lan_do_manage();
            if(n_lansta.Sta == NET_DOWN && M26_get_sta() == M26_GRMS_ESTABLISHED) {
                net4G_do_manage();
            }
    		_TICK_SLEEP(t);
            if(init > 0) {
                init--;
                if(init == 0 || n_lansta.Sta == NET_UP || n_4gsta.Sta == NET_UP) {
                    init=0;
                    t = 30;
                }
            }
    	}
        usleep(200*1000);
    }
}


unsigned char visit_lan_sta(void) {
    return n_lansta.Sta;
}

void net_manage_int(void)
{
    struct netsta *n = &n_lansta;
    char buf[32];
    unsigned char res = 0;
    unsigned int sip = cfgget_sip();
    sprintf(buf, "%d.%d.%d.%d", sip>>24, (sip>>16)&0xff, (sip>>8)&0xff, sip&0xff);
    if( 0 != _sys_ping_res(buf, n->ifname)) { 
        res = 1;
    }
    printf("net manage init, res = %d\n", res);
    if(res) {
        _do_addremove_route(100);
    }
}


 void creat_net_manage(void)
{
	pthread_t threads;
	int rc;
	long t=0;
	rc = pthread_create(&threads, NULL, net_manage, (void *)t);
	if (rc){
		printf("ERROR; return code from pthread_create() is %d\n", rc);
		exit(-1);
	}
}




